#include <cstdio>
#include <cstring>
#include <cmath>

#include "map.h"

#ifndef MAPGEN
#include "error.h"
#include "game_engine.h"
#endif

map::map(unsigned int w,unsigned int h):
    width(w),height(h){
    data = new map_elem[w*h];
}
map::~map(){
    delete[] data;
}

unsigned int map::getWidth(){ return width; }
unsigned int map::getHeight(){ return height; }
map_elem* map::elem(unsigned int x,unsigned int y){
    if( x >= width || y >= height ) return NULL;
    return &data[x + width*y];
}
map_elem* map::elem(uicoord uic){
    if( uic.x >= width || uic.y >= height ) return NULL;
    return &data[uic.x + width*uic.y];
}

uicoord map::round(fcoord input){
    uicoord output;
    output.x = input.x;
    output.y = input.y;
    if( fmod( input.x,1 ) >= 0.5 ) output.x ++;
    if( fmod( input.y,1 ) >= 0.5 ) output.y ++;
    return output;
}
fcoord map::toFloat(uicoord input){
    fcoord output;
    output.x = float(input.x);
    output.y = float(input.y);
    return output;
}
fcoord map::revert(fcoord input){
    fcoord output;
    input.x = float(input.x - float(XBASE))/float(XWID/2);
    input.y = float(input.y - float(YBASE))/float(YWID/2);
    output.x = (input.x - input.y)/2.0;
    output.y = (input.x + input.y)/(-2.0);
    return output;
}
fcoord map::convert(fcoord input){
    fcoord output;
    output.x = XBASE + (input.x-input.y)*float(XWID/2);
    output.y = YBASE - (input.x+input.y)*float(YWID/2);// + stel->level;
    return output;
}
fcoord map::convert(uicoord input){
    fcoord output;
    output.x = XBASE + (float(input.x)-float(input.y))*(XWID/2);
    output.y = YBASE - (float(input.x)+float(input.y))*(YWID/2);// + stel->level;
    return output;
}
uicoord map::translate(uicoord input,int x,int y){
    uicoord output = input;
    output.x += x;
    output.y += y;
    return output;
}
fcoord map::translate(fcoord input,float x,float y){
    fcoord output = input;
    output.x += x;
    output.y += y;
    return output;
}
fcoord map::convertOff(fcoord input){
    fcoord output;
    output.x = input.x*0.5;
    output.y = input.y*0.5;
    return output;
}
fcoord map::convertOff(uicoord input){
    fcoord output;
    output.x = float(input.x)*0.5;
    output.y = float(input.y)*0.5;
    return output;
}

void map::setSizes(unsigned int w,unsigned int h){
    width = w;
    height = h;
    delete[] data;
    data = new map_elem[w*h];
}
void map::setElem(unsigned int x,unsigned int y,map_elem* el){
    memcpy( &data[x + width*y], el, sizeof( map_elem ) );
}

map* map::loadMap(file* fil){
    map_fileheader hdr;
    fil->read(&hdr,1,sizeof(map_fileheader));
    if( strncmp( (char*)hdr.idstring, "MAPF", 4 ) ){
        printf("Erreur\n");
        return NULL;
    }
    map* outmap = new map( hdr.width, hdr.height );
    fil->read(outmap->elem(0,0), hdr.height * hdr.width, sizeof(map_elem));
    return outmap;
}
bool map::saveMap(file* fil,map* mp){
    map_fileheader hdr;
    strncpy( (char*)hdr.idstring, "MAPF", 4 );
    hdr.height = mp->getHeight();
    hdr.width = mp->getWidth();
    fil->write( &hdr, 1, sizeof(map_fileheader) );
    fil->write( mp->elem(0,0), hdr.height * hdr.width, sizeof(map_elem));
    return true;
}

bool map::isWalkable(map_elem* el){
    if( !el ) return false;
    if( el->status & sta_static_obs ) return false;
    if( (el->status & sta_bldg) && (!(el->status & sta_bldg_ntr)) ) return false;
    return true;
}
bool map::isBuildable(map_elem* el){
    return isWalkable(el);
}
